/// @file unrootedtree.hh
/// @brief Definitions for the unrooted tree classes

// *************************************************************************

// Copyright© 2010 Texas A&M University, 
//                 College Station, Texas
//                 Contact: R Crosby <rwc@cs.tamu.edu>
//
// Copyright© 2003, 2004 by BiRC -- Bioinformatics Research Center
//                 University of Aarhus, Denmark
//                 Contact: Thomas Mailund <mailund@birc.dk>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// *************************************************************************

#ifndef UNROOTEDTREE_HH
#define UNROOTEDTREE_HH

#include <vector>
#include <list>

class UnrootedTree;
class UnrootedTreeVisitor;
class S;

// *********************************************************************

class UnrootedTreeNode {

    friend class UnrootedTreeLeaf;
    friend class UnrootedTreeInner;
    virtual void add_neighbour    ( UnrootedTreeNode* utn         ) = 0;
    virtual void replace_neighbour( UnrootedTreeNode* original,
				    UnrootedTreeNode* replacement ) = 0;

public:

    virtual ~UnrootedTreeNode() {}
    virtual void connect ( UnrootedTreeNode*    utn);
    virtual void accept  ( UnrootedTreeVisitor* visitor  ) = 0;
    virtual void build   ( UnrootedTree*        ut, 
			   UnrootedTreeNode*    prev = 0 ) = 0;

};

// *********************************************************************

class UnrootedTreeLeaf : public UnrootedTreeNode {
private:

    UnrootedTreeNode *_neighbour;
    S * const         _s;

    void add_neighbour     ( UnrootedTreeNode *utn );
    void replace_neighbour ( UnrootedTreeNode *original,
			     UnrootedTreeNode *replacement );
    
public:

    UnrootedTreeLeaf ( S *s ) 
	: _neighbour(0), _s(s) { }

    S *                s        () { return _s; };
    UnrootedTreeNode * neighbour() { return _neighbour; }
    void               accept   ( UnrootedTreeVisitor * visitor);
    void               build    ( UnrootedTree *        ut, 
				  UnrootedTreeNode *    prev = 0);
};

// *********************************************************************

class UnrootedTreeInner : public UnrootedTreeNode {
private:
    vector<UnrootedTreeNode *> _neighbours;
    void add_neighbour(UnrootedTreeNode *utn);
    void replace_neighbour(UnrootedTreeNode *original,
			   UnrootedTreeNode *replacement);

public:
    UnrootedTreeInner() : _neighbours(0) {}
    virtual ~UnrootedTreeInner() {}
    vector<UnrootedTreeNode *> &neighbours() { return _neighbours; }
    void accept(UnrootedTreeVisitor *visitor);
    void build(UnrootedTree *ut, UnrootedTreeNode *prev = 0);
};

// *********************************************************************

class UnrootedTree {
private:

    list<UnrootedTreeNode *> _nodes;
    list<UnrootedTreeLeaf *> _leafs;

public:

    UnrootedTree(UnrootedTreeNode *utn )   { utn->build(this); }
    ~UnrootedTree();


    list<UnrootedTreeLeaf *> &leafs()      { return _leafs; }
    list<UnrootedTreeNode *> &nodes()      { return _nodes; }

};

// *********************************************************************

//FIXME Not really a visitor - since it itself handles how to recurse
//through the tree -- kind of ugly, might find a way to change it

class UnrootedTreeVisitor {
private:
public:
    virtual ~UnrootedTreeVisitor() {};
    virtual void visit_leaf(UnrootedTreeLeaf *leaf) = 0;
    virtual void visit_inner(UnrootedTreeInner *inner) = 0;
};

#endif // UNROOTEDTREE_HH
